﻿using System;
using System.Net.Mail;
using System.Text;
using SOM.AbstractDALFactory;
using SOM.ConcreteDAL;
using SOM.ConcreteDALFactory;
using SOM.Model;
using SOM.Security;

namespace SOM.ConcreteBL
{
    public class UsuarioBL
    {
        private readonly SOMAbstractDALFactory _factory;
        private readonly UsuarioDAL _usuarioDAL;
        private readonly SOMEntities _contexto;

        public UsuarioBL()
        {
            _factory = new SOMConcreteDALFactory();
            _usuarioDAL = Factory.CreateUsuarioDAL();
            _contexto = new SOMEntities();
        }

        private SOMAbstractDALFactory Factory
        {
            get { return _factory; }
        }

        private UsuarioDAL UsuarioDAL
        {
            get { return _usuarioDAL; }
        }

        /// <summary>
        /// Carrega um usuário através do seu nickname.
        /// </summary>
        /// <param name="dsNickname"></param>
        /// <returns></returns>
        public Usuario Load(string dsNickname)
        {
            UsuarioDAL usuarioDAL = _factory.CreateUsuarioDAL();
            return usuarioDAL.Load(dsNickname, _contexto);
        }

        /// <summary>
        /// Verifica se um usuário já está cadastrado
        /// </summary>
        /// <param name="nickname"></param>
        /// <returns></returns>
        public bool UsuarioExiste(string nickname)
        {
            Usuario usuario = UsuarioDAL.FindByNickname(nickname);

            if (usuario == null)
                return false;
            else
                return true;
        }

        /// <summary>
        /// Verifica se um email existe
        /// </summary>
        /// <param name="email"></param>
        /// <returns></returns>
        public bool EmailExiste(string email)
        {
            return UsuarioDAL.EmailExiste(email);

        }

        /// <summary>
        /// Verifica se o email já existe.
        /// </summary>
        /// <param name="cpf"></param>
        /// <returns></returns>
        public bool CpfExiste(string cpf)
        {
            return UsuarioDAL.CpfExiste(cpf);
        }

        /// <summary>
        /// Exclui um usuário e retorna a confirmação da exclusão.
        /// </summary>
        /// <param name="usuario"></param>
        /// <param name="senha"></param>
        public bool Delete(string nickname, string senha)
        {
            UsuarioDAL usuarioDAL = _factory.CreateUsuarioDAL();
            Usuario usuario = usuarioDAL.Load(nickname, _contexto);

            if (!usuario.usr_senha.Equals(SOMSecurity.MD5Criptografar(senha)))
                return false;

            UsuarioDAL.Delete(usuario, _contexto);
            return true;
        }

        /// <summary>
        /// Exclui um usuário
        /// </summary>
        /// <param name="dsNickname"></param>
        /// <returns></returns>
        public bool Delete(string dsNickname)
        {
            UsuarioDAL usuarioDAL = _factory.CreateUsuarioDAL();
            Usuario usuario = usuarioDAL.Load(dsNickname, _contexto);

            UsuarioDAL.Delete(usuario, _contexto);
            return true;
        }

        /// <summary>
        /// Atualiza um usuário.
        /// </summary>
        /// <param name="usuario"></param>
        public void Update(Usuario usuario)
        {
            UsuarioDAL usuarioDAL = _factory.CreateUsuarioDAL();
            usuarioDAL.Update(usuario, _contexto);
        }

        /// <summary>
        /// Insere um usuário.
        /// </summary>
        /// <param name="usuario"></param>
        public void Insert(Usuario usuario)
        {
            UsuarioDAL usuarioDAL = _factory.CreateUsuarioDAL();
            usuarioDAL.Insert(usuario, _contexto);
        }

        /// <summary>
        /// Verifica se um CPF é válido.
        /// </summary>
        /// <param name="vrCPF"></param>
        /// <returns></returns>
        public bool ValidarCPF(string vrCPF)
        {
            string valor = vrCPF.Replace(".", "");
            valor = valor.Replace("-", "");

            if (valor.Length != 11)
                return false;

            bool igual = true;
            for (int i = 1; i < 11 && igual; i++)
                if (valor[i] != valor[0])
                    igual = false;

            if (igual || valor == "12345678909")
                return false;

            int[] numeros = new int[11];

            for (int i = 0; i < 11; i++)
                numeros[i] = int.Parse(
                  valor[i].ToString());

            int soma = 0;
            for (int i = 0; i < 9; i++)
                soma += (10 - i) * numeros[i];

            int resultado = soma % 11;

            if (resultado == 1 || resultado == 0)
            {
                if (numeros[9] != 0)
                    return false;
            }
            else if (numeros[9] != 11 - resultado)
                return false;

            soma = 0;
            for (int i = 0; i < 10; i++)
                soma += (11 - i) * numeros[i];

            resultado = soma % 11;

            if (resultado == 1 || resultado == 0)
            {
                if (numeros[10] != 0)
                    return false;
            }
            else
                if (numeros[10] != 11 - resultado)
                    return false;

            return true;
        }

        /// <summary>
        /// Reseta a senha do usuário.
        /// </summary>
        /// <param name="cpf">CPF do usuário</param>
        /// <param name="email">Email do usuário</param>
        /// <returns>True caso as informações estejam corretas. False caso contrário.</returns>
        public bool ResetarSenha(string cpf, string email)
        {
            Usuario usuario = _usuarioDAL.FindByCpf(cpf);
            usuario = _usuarioDAL.Load(usuario.usr_ds_nickname, _contexto);

            if (usuario == null)
            {
                return false;
            }

            if (!usuario.usr_ds_email.Equals(email))
            {
                return false;
            }

            Random random = new Random();

            string chaveSenha = random.Next(1, 999999).ToString();
            string novaSenha = usuario.usr_ds_nickname + chaveSenha;
            string senhaAntiga = usuario.usr_senha;

            usuario.usr_senha = SOMSecurity.MD5Criptografar(novaSenha);
            _usuarioDAL.Update(usuario, _contexto);

            EnviarEmailUsuario(usuario,senhaAntiga,novaSenha);

            return true;
        }

        /// <summary>
        /// Envia um email para o usuario com a nova senha.
        /// </summary>
        /// <param name="usuario"></param>
        /// <param name="novaSenha"></param>
        private void EnviarEmailUsuario(Usuario usuario, string senhaAntiga,string novaSenha)
        {

            SmtpClient smtpClient = new SmtpClient();
            smtpClient.EnableSsl = true;

            MailAddress emailRemetente = new MailAddress("administrador@somproject.org");

            MailAddress emailDestinatario = new MailAddress(usuario.usr_ds_email.Trim());

            MailMessage mensagem = new MailMessage(emailRemetente, emailDestinatario);
            mensagem.IsBodyHtml = true;

            mensagem.Subject = "Recuperação de senha";

            StringBuilder conteudoMensagem = new StringBuilder();
            conteudoMensagem.Append("Caro " + usuario.usr_nm_usuario + ",<br/>");
            conteudoMensagem.Append(
                "você solicitou recetemente o reenvio da sua senha para acesso ao sistema de ouvidoria online. ");
            conteudoMensagem.Append("Suas novas informações de acesso são: <br/>");
            conteudoMensagem.Append("Usuario: <b>" + usuario.usr_ds_nickname + "</b><br/>");
            conteudoMensagem.Append("Senha: <b>" + novaSenha + "</b>");

            mensagem.Body = conteudoMensagem.ToString();
            try
            {
                smtpClient.Send(mensagem);
            }
            catch (Exception)
            {
                //conserva o valor antigo da senha do usuário
                usuario.usr_senha = senhaAntiga;
                _usuarioDAL.Update(usuario,_contexto);
                
                throw new SmtpException();
            }
        }
    }
}
